namespace FIREFLYX {
    export interface HtmlImageSuffix {
        // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility, quotes
        '.hi.jpg': string;
        // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility, quotes
        '.hi.png': string;
        // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility, quotes
        '.hi.wbp': string;
    }

    /**
     * 天空盒 样例
     */
    export class SkyBox implements IExample {
        private MakeCubeMapTestShader() {
            //使用 屏幕空间阴影图计算阴影
            const vsCode1 = `#version 300 es
        precision mediump float;
        layout (location = 0) in vec4 a_Position;   //顶点 位置 是有默认值的 (0,0,0,1)
        uniform ubo_model_block{
            mat4 u_mMtx;                            //模型矩阵
        } uboModel;
        uniform ubo_cam_block{
            mat4 u_viewMtx;                         //视窗矩阵
            mat4 u_projectMtx;                      //投影矩阵
            vec4 u_eyePos;                          //眼睛位置
        } uboCam;

        out vec3 v_normal;
        void main() {
            mat4 mvpMat = uboCam.u_projectMtx * uboCam.u_viewMtx * uboModel.u_mMtx;
            gl_Position = mvpMat * a_Position;

            v_normal = normalize(a_Position.xyz);
        }
        `;

            const fsCode1 = `#version 300 es
        precision mediump float;
        uniform samplerCube u_mainTexCube;

        in vec3 v_normal;
        out vec4 color;

        void main(){
            vec4 texColor = texture(u_mainTexCube , normalize(v_normal));
            color = texColor;
        }
        `;

            //glsl
            const vs = new GLSL();
            vs.setCode(vsCode1);
            const fs = new GLSL();
            fs.setCode(fsCode1);

            //shader
            let result: Shader = new Shader();
            result.tag = `custom_cube_texture`;
            result.lightMode = RenderPipeline.LM_FORWARD;
            result.vertexGLSL = vs;
            result.fragmentGLSL = fs;
            //unifrom 默认值
            result.definePropertyMap = {};

            //apply
            result.apply();

            return result;
        }

        private async MakeTestCubeMap(gl: WebGL2RenderingContext) {
            const faceInfos = [
                { target: gl.TEXTURE_CUBE_MAP_POSITIVE_X, faceColor: `#F00`, textColor: `#0FF`, text: `+X` },
                { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X, faceColor: `#FF0`, textColor: `#00F`, text: `-X` },
                { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y, faceColor: `#0F0`, textColor: `#F0F`, text: `+Y` },
                { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, faceColor: `#0FF`, textColor: `#F00`, text: `-Y` },
                { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z, faceColor: `#00F`, textColor: `#FF0`, text: `+Z` },
                { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, faceColor: `#F0F`, textColor: `#0F0`, text: `-Z` },
            ];

            //
            const cubeMap = new TextureCube("cubeMap");
            //
            const ctx = document.createElement("canvas").getContext("2d");
            let size = 128;
            ctx.canvas.width = size;
            ctx.canvas.height = size;

            //创建一个纹理
            const generateFace = (ctx, faceColor, textColor, text) => {
                const { width, height } = ctx.canvas;
                ctx.fillStyle = faceColor;
                ctx.fillRect(0, 0, width, height);
                ctx.font = `${width * 0.7}px sans-serif`;
                ctx.textAlign = `center`;
                ctx.textBaseline = `middle`;
                ctx.fillStyle = textColor;
                ctx.fillText(text, width / 2, height / 2);
            };

            //生成 image
            faceInfos.forEach((faceInfo) => {
                const { target, faceColor, textColor, text } = faceInfo;
                generateFace(ctx, faceColor, textColor, text);
                cubeMap.setTextureData(ctx.canvas, target);    //设置数据到 cubemap
            });

            //cubeMap 
            cubeMap.paramSetting.mipmap = true;
            cubeMap.apply();

            return cubeMap;
        }

        private makeModel(mesh: Mesh, cubeMap: TextureCube, sh: Shader) {
            let model = new GameObject("model");
            const mr = model.addComponent<MeshRenderer>(MeshRenderer);
            const baseMtr = new Material();
            mr.materialGroup[0] = baseMtr;
            mr.mesh = mesh;
            baseMtr.shader = sh;
            baseMtr.rasterState = RasterState.getState(CullMode.BACK);
            baseMtr.setProperty(`u_mainTexCube`, cubeMap);

            return model;
        }

        public async Init(canvas: HTMLCanvasElement) {
            const gl = canvas.getContext("webgl2");
            //app init
            App.init(gl.canvas as any);
            //简单观察相机
            const cVEnv = GenCamViewEnv();
            const cam = cVEnv.camera;
            const camHover = cVEnv.camHover;
            //
            //cube Map
            let cubeMap0 = await this.MakeTestCubeMap(gl);
            let cubeMap1 = await LoadCubeMapByHtmlImages(`01`, `.hi.jpg`);
            //test set mipmap
            cubeMap0.paramSetting.mipmap = true;
            cubeMap0.apply();
            cubeMap1.paramSetting.mipmap = true;
            cubeMap1.apply();

            //SKY BOX Material
            AttachSkyBox(cubeMap1);
            cam.clearMode = CameraClearMode.SKY_BOX;    //相机设置 SKY_BOX

            //shader
            const bSh = this.MakeCubeMapTestShader();
            //create mesh
            const model = this.makeModel(DefaultAsset.GetMesh(DefMesh.SPHERE), cubeMap1, bSh);
            //
            const model1 = this.makeModel(DefaultAsset.GetMesh(DefMesh.CUBE), cubeMap0, bSh);
            model1.transform.position = new Vector3(0, 1.5, 0);

            // let angles = new Vector3(0,0,90 * Math.PI / 180);
            let angles = new Vector3();
            let speed = 0.1;

            GlobalEventManager.Instance.addListener("sceneUpdate", (dt: number) => {
                //旋转
                Quaternion.RotationYawPitchRollToRef(angles.y, angles.x, angles.z, model.transform.rotation);
                model.transform.rotation = model.transform.rotation;
            }, this);

            //IO Event
            //键盘控制旋转
            GlobalEventManager.Instance.addListener("keydown", (ev: KeyboardEvent) => {
                console.log(`onkeydown : ${ev.key} `);
                let dt = 1 * speed;
                switch (ev.key) {
                    case "a": angles.x += dt; break;
                    case "w": angles.y += dt; break;
                    case "s": angles.z += dt; break;
                    default:
                }
            }, this);
        }
    }
}